1
'*************************** Module Header ******************************'
2 ' Module Name: FTPDownloadClient.vb
3 ' Project: VBFTPDownload
4 ' Copyright (c) Microsoft Corporation.
6 ' This class is used to download files from a FTP server. When the download
7 ' starts, it will download the file in a background thread. The downloaded
8 ' data is stored in a MemoryStream first, and then written to local file.
11 ' This source is subject to the Microsoft Public License.
12 ' See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
13 ' All other rights reserved.
15 ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
16 ' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
17 ' WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
18 '*************************************************************************'
22 Imports System
.Threading
24 Partial
Public Class FTPClientManager
26 Public Class FTPDownloadClient
28 Public Const MaxCacheSize
As Integer = 2097152
31 Public Const BufferSize
As Integer = 2048
33 Private _manager
As FTPClientManager
35 Public Event FileDownloadCompleted
As EventHandler(Of FileDownloadCompletedEventArgs
)
37 Public Event AllFilesDownloadCompleted
As EventHandler
39 Public Sub New(ByVal manager
As FTPClientManager
)
40 If manager Is
Nothing Then
41 Throw
New ArgumentNullException("FTPClientManager cannot be null.")
48 ''' Download files, directories and their subdirectories.
50 Public Sub DownloadDirectoriesAndFiles(ByVal files
As IEnumerable(Of FTPFileSystem
),
51 ByVal localPath
As String)
52 If files Is
Nothing Then
53 Throw
New ArgumentNullException("The files to download cannot be null.")
56 ' Create a thread to download data.
57 Dim threadStart
As New ParameterizedThreadStart(
58 AddressOf StartDownloadDirectoriesAndFiles
)
59 Dim downloadThread
As New Thread(threadStart
)
60 downloadThread
.IsBackground
= True
61 downloadThread
.Start(New Object() {files
, localPath
})
65 ''' Download files, directories and their subdirectories.
67 Private Sub StartDownloadDirectoriesAndFiles(ByVal state
As Object)
68 Dim paras
= TryCast(state
, Object())
70 Dim files
As IEnumerable(Of FTPFileSystem
) = TryCast(paras(0),
71 IEnumerable(Of FTPFileSystem
))
72 Dim localPath
As String = TryCast(paras(1), String)
74 For Each file
In files
75 DownloadDirectoryOrFile(file
, localPath
)
78 Me.OnAllFilesDownloadCompleted(EventArgs
.Empty
)
82 ''' Download a single file or directory.
84 Private Sub DownloadDirectoryOrFile(ByVal fileSystem
As FTPFileSystem
,
85 ByVal localPath
As String)
87 ' Download the file directly.
88 If Not fileSystem
.IsDirectory
Then
89 DownloadFile(fileSystem
, localPath
)
91 ' Download a directory.
94 ' Construct the directory Path.
95 Dim directoryPath
As String = localPath
& "\" & fileSystem
.Name
97 If Not Directory
.Exists(directoryPath
) Then
98 Directory
.CreateDirectory(directoryPath
)
101 ' Get the sub directories and files.
102 Dim subDirectoriesAndFiles
=
103 Me._manager
.GetSubDirectoriesAndFiles(fileSystem
.Url
)
105 ' Download the files in the folder and sub directories.
106 For Each subFile
In subDirectoriesAndFiles
107 DownloadDirectoryOrFile(subFile
, directoryPath
)
113 ''' Download a single file directly.
115 Private Sub DownloadFile(ByVal file
As FTPFileSystem
, ByVal localPath
As String)
116 If file
.IsDirectory
Then
117 Throw
New ArgumentException(
118 "The FTPFileSystem to download is a directory in fact")
121 Dim destPath
As String = localPath
& "\" & file
.Name
123 ' Create a request to the file to be downloaded.
124 Dim request
As FtpWebRequest
=
125 TryCast(WebRequest
.Create(file
.Url
), FtpWebRequest
)
127 request
.Credentials
= Me._manager
.Credentials
130 request
.Method
= WebRequestMethods
.Ftp
.DownloadFile
132 Dim response
As FtpWebResponse
= Nothing
133 Dim responseStream
As Stream
= Nothing
134 Dim downloadCache
As MemoryStream
= Nothing
139 ' Retrieve the response from the server and get the response stream.
140 response
= TryCast(request
.GetResponse(), FtpWebResponse
)
142 Me._manager
.OnNewMessageArrived(New NewMessageEventArg _
143 With {.NewMessage
= response
.StatusDescription
})
145 responseStream
= response
.GetResponseStream()
147 ' Cache data in memory.
148 downloadCache
= New MemoryStream(FTPDownloadClient
.MaxCacheSize
)
149 Dim downloadBuffer(FTPDownloadClient
.BufferSize
- 1) As Byte
151 Dim bytesSize
As Integer = 0
152 Dim cachedSize
As Integer = 0
154 ' Download the file until the download is completed.
157 ' Read a buffer of data from the stream.
159 responseStream
.Read(downloadBuffer
, 0, downloadBuffer
.Length
)
161 ' If the cache is full, or the download is completed, write
162 ' the data in cache to local file.
163 If bytesSize
= 0 OrElse MaxCacheSize
< cachedSize
+ bytesSize
Then
165 ' Write the data in cache to local file.
166 WriteCacheToFile(downloadCache
, destPath
, cachedSize
)
168 ' Stop downloading the file if the download is paused,
169 ' canceled or completed.
170 If bytesSize
= 0 Then
175 downloadCache
.Seek(0, SeekOrigin
.Begin)
177 Catch ex
As Exception
179 String.Format("There is an error while downloading {0}. " _
180 & " See InnerException for detailed error. ",
182 Dim errorException
As New ApplicationException(msg
, ex
)
184 ' Fire the DownloadCompleted event with the error.
185 Dim e
As ErrorEventArgs
= New ErrorEventArgs _
186 With {.ErrorException
= errorException
}
188 Me._manager
.OnErrorOccurred(e
)
195 ' Write the data from the buffer to the cache in memory.
196 downloadCache
.Write(downloadBuffer
, 0, bytesSize
)
197 cachedSize
+= bytesSize
200 Dim fileDownloadCompletedEventArgs_Renamed
=
201 New FileDownloadCompletedEventArgs _
202 With {.LocalFile
= New FileInfo(destPath
), .ServerPath
= file
.Url
}
204 Me.OnFileDownloadCompleted(fileDownloadCompletedEventArgs_Renamed
)
206 If response IsNot
Nothing Then
210 If responseStream IsNot
Nothing Then
211 responseStream
.Close()
214 If downloadCache IsNot
Nothing Then
215 downloadCache
.Close()
221 ''' Write the data in cache to local file.
223 Private Sub WriteCacheToFile(ByVal downloadCache
As MemoryStream
,
224 ByVal downloadPath
As String,
225 ByVal cachedSize
As Integer)
226 Using fileStream_Renamed
As New FileStream(downloadPath
, FileMode
.Append
)
227 Dim cacheContent(cachedSize
- 1) As Byte
228 downloadCache
.Seek(0, SeekOrigin
.Begin)
229 downloadCache
.Read(cacheContent
, 0, cachedSize
)
230 fileStream_Renamed
.Write(cacheContent
, 0, cachedSize
)
234 Protected Overridable
Sub OnFileDownloadCompleted(ByVal e
As FileDownloadCompletedEventArgs
)
236 RaiseEvent FileDownloadCompleted(Me, e
)
239 Protected Overridable
Sub OnAllFilesDownloadCompleted(ByVal e
As EventArgs
)
240 RaiseEvent AllFilesDownloadCompleted(Me, e
)